/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {BUILD_PROFILE_JSON5, parseJsonText, Scene} from 'arkanalyzer';
import { Defects, MatcherCallback, Rule } from '../../Index';
import { BaseChecker, BaseMetaData } from '../BaseChecker';
import { IssueReport } from '../../model/Defects';
import { existsSync } from 'fs';
import path from 'path';
import fs from 'fs';
import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger';

const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'DarkColorModeCheck');

const gMetaData: BaseMetaData = {
    severity: 3,
    ruleDocPath: 'docs/dark-color-mode-check.md',
    description: 'Implement dark mode adaptation for reduced power consumption.'
};

const DEFAULT_DARK_COLOR_FILE_PATH = './dark/element/color.json';
const DEFAULT_RESOURCES_PATH = './src/main/resources';
const DEFAULT_MODULE_JSON5_PATH = './src/main/module.json5';

export class DarkColorModeCheck implements BaseChecker {
    readonly metaData: BaseMetaData = gMetaData;
    public rule: Rule;
    public defects: Defects[] = [];
    public issues: IssueReport[] = [];

    public registerMatchers(): MatcherCallback[] {
        const matchBuildCb: MatcherCallback = {
            matcher: undefined,
            callback: this.check
        };
        return [matchBuildCb];
    }

    public check = (scene: Scene): void => {
        for (let [key, value] of scene.getModuleSceneMap()) {
            this.checkModule(value.getModulePath());
        }
    };

    private checkModule(modulePath: string): void {
        if (!existsSync(modulePath)) {
            return;
        }
        const buildProfilePath = path.join(modulePath, BUILD_PROFILE_JSON5);
        const absModuleJson5Path: string = path.join(modulePath, DEFAULT_MODULE_JSON5_PATH);
        const absDefaultColorPath: string = path.join(modulePath, DEFAULT_RESOURCES_PATH, DEFAULT_DARK_COLOR_FILE_PATH);
        const resDirs: string[] = this.getResourcesDirs(buildProfilePath);
        let reportFlag: boolean = true;
        // no resource directories configured in targets, or buildProfilePath is not exist
        if (resDirs.length === 0 && existsSync(absDefaultColorPath)) {
            reportFlag = false;
        }
        // resource directories configured in targets
        resDirs.forEach((resDir) => {
            const colorPath: string = path.join(modulePath, resDir, DEFAULT_DARK_COLOR_FILE_PATH);
            if (existsSync(colorPath)) {
                reportFlag = false;
            }
        });
        if (reportFlag) {
            this.reportIssue(absModuleJson5Path);
        }
    }

    private getResourcesDirs(buildProfilePath: string): string[] {
        let dirs: string[] = [];
        if (!existsSync(buildProfilePath)) {
            return dirs;
        }
        let configText: string = '';
        try {
            configText = fs.readFileSync(buildProfilePath, 'utf8');
        } catch (error) {
            logger.error(`Error reading file: ${error}`);
        }
        const buildProfileJson = parseJsonText(configText);
        const targets = buildProfileJson.targets;
        if (targets instanceof Array) {
            targets.forEach(target => {
                if (target.name === 'default') {
                    dirs.push(...(target.resource?.directories || []));
                }
            });
        }
        return dirs;
    }

    private reportIssue(filePath: string): void {
        let severity = this.rule.alert ?? this.metaData.severity;
        let defects = new Defects(0, 0, 0, this.metaData.description, severity, this.rule.ruleId,
            filePath, this.metaData.ruleDocPath, true, false, false, false);
        this.issues.push(new IssueReport(defects, undefined));
    }
}